既然我們已經有了 db.Store interface,我們可以使用 gomock 生成 mock interface。
首先,我將在 db 套件內創建一個新的 mock 文件夾。接著,打開終端機並執行:
mkdir -p db/mock
mockgen -help
mockgen 提供了兩種方式生成mocks:
mockgen 使用反射自動完成。選擇使用 Reflect mode 並執行以下命令:
Store Interface的導入路徑 (github.com/Kcih4518/simpleBank_2023/db/sqlc)。Interface Name,即 Store 。destination是指定生成輸出文件的目的地: db/mock/store.go
package 指定的package name (mockdb)mockgen -build_flags=--mod=mod -destination db/mock/store.go -package mockdb github.com/Kcih4518/simpleBank_2023/db/sqlc Store
回到 Visual Studio Code,我們可以看到在 db/mock 文件夾內生成了一個新的 store.go 文件。
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/Kcih4518/simpleBank_2023/db/sqlc (interfaces: Store)
// Package mockdb is a generated GoMock package.
package mockdb
import (
context "context"
reflect "reflect"
db "github.com/Kcih4518/simpleBank_2023/db/sqlc"
gomock "github.com/golang/mock/gomock"
)
// MockStore is a mock of Store interface.
type MockStore struct {
ctrl *gomock.Controller
recorder *MockStoreMockRecorder
}
// MockStoreMockRecorder is the mock recorder for MockStore.
type MockStoreMockRecorder struct {
mock *MockStore
}
// NewMockStore creates a new mock instance.
func NewMockStore(ctrl *gomock.Controller) *MockStore {
mock := &MockStore{ctrl: ctrl}
mock.recorder = &MockStoreMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStore) EXPECT() *MockStoreMockRecorder {
return m.recorder
}
...
這個文件中有兩個重要的結構:MockStore 和 MockStoreMockRecorder。
MockStore:實現了 Store Interface的所有必需功能。MockStoreMockRecorder:用於建立stubs,可以指定應該呼叫 AddAccountBalance() 函數多少次,以及參數的值。// AddAccountBalance mocks base method.
func (m *MockStore) AddAccountBalance(arg0 context.Context, arg1 db.AddAccountBalanceParams) (db.Account, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddAccountBalance", arg0, arg1)
ret0, _ := ret[0].(db.Account)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddAccountBalance indicates an expected call of AddAccountBalance.
func (mr *MockStoreMockRecorder) AddAccountBalance(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAccountBalance", reflect.TypeOf((*MockStore)(nil).AddAccountBalance), arg0, arg1)
}
在開始使用新生成的 MockStore 寫API測試之前,我會在 Makefile 中添加一個新的 mock 命令,這樣我們可以隨時重新生成代碼。
mock:
mockgen -build_flags=--mod=mod -destination db/mock/store.go -package mockdb github.com/Kcih4518/simpleBank_2023/db/sqlc Store
.PHONY: postgres createdb dropdb migrateup migratedown sqlc test server mock
現在,每當我們想重新生成 mock store,我們可以簡單地在終端機中運行 make mock。
MockStore Struct 是Store Interface的implementation ?
為了確定 MockStore 是否實現了 Store Interface的每個方法,您需要將 MockStore 的方法與 Store 介面中定義的方法進行比較。如果 MockStore 對於 Store 中的每個方法都有相應的方法,且每個方法都有正確的Signature(函數名稱、它的參數類型列表和它的返回值類型),那麼 MockStore 就完全實現了 Store 介面。
db/sqlc/store.go
type Store interface {
Querier
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
}
db/sqlc/querier.go
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.20.0
package db
import (
"context"
)
type Querier interface {
AddAccountBalance(ctx context.Context, arg AddAccountBalanceParams) (Account, error)
CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error)
CreateEntry(ctx context.Context, arg CreateEntryParams) (Entry, error)
CreateTransfer(ctx context.Context, arg CreateTransferParams) (Transfer, error)
DeleteAccount(ctx context.Context, id int64) error
GetAccount(ctx context.Context, id int64) (Account, error)
GetAccountForUpdate(ctx context.Context, id int64) (Account, error)
GetEntry(ctx context.Context, id int64) (Entry, error)
GetTransfer(ctx context.Context, id int64) (Transfer, error)
ListAccounts(ctx context.Context, arg ListAccountsParams) ([]Account, error)
ListEntries(ctx context.Context, arg ListEntriesParams) ([]Entry, error)
ListTransfers(ctx context.Context, arg ListTransfersParams) ([]Transfer, error)
UpdateAccount(ctx context.Context, arg UpdateAccountParams) (Account, error)
}
var _ Querier = (*Queries)(nil)
db/mock/store.go
func (m *MockStore) AddAccountBalance(arg0 context.Context, arg1 db.AddAccountBalanceParams) (db.Account, error)
func (m *MockStore) CreateAccount(arg0 context.Context, arg1 db.CreateAccountParams) (db.Account, error)
func (m *MockStore) CreateTransfer(arg0 context.Context, arg1 db.CreateTransferParams) (db.Transfer, error)
func (m *MockStore) TransferTx(arg0 context.Context, arg1 db.TransferTxParams) (db.TransferTxResult, error)
...